package com.automapper.sqlfragment;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Table;
import javax.persistence.criteria.JoinType;

import org.apache.commons.lang3.StringUtils;

import com.automapper.constants.FetchMode;
import com.automapper.criterion.ExpressionContext;
import com.automapper.exception.AutoMapperException;
import com.automapper.utils.FieldFacade;
import com.automapper.utils.ObjectFacade;

public class SqlFragmentAssembler {
	
	private ObjectFacade objectFacade;
	
	private String table;
	private String alias;
	
	private FetchMode fetchMode;
	private JoinType joinType;
	
	private ExpressionContext expressionContext;
	private SqlFragmentAssembler cascadeSqlFragmentAssembler;
	
	public SqlFragmentAssembler(Class<?> clazz, String table, String alias, FetchMode fetchMode, ExpressionContext expressionContext) throws Exception {
		this(clazz, table, alias, fetchMode, null, expressionContext);
	}
	
	public SqlFragmentAssembler(Class<?> clazz, String table, String alias, JoinType joinType, ExpressionContext expressionContext) throws Exception {
		this(clazz, table, alias, null, joinType, expressionContext);
	}

	private SqlFragmentAssembler(Class<?> clazz, String table, String alias, FetchMode fetchMode,
			JoinType joinType, ExpressionContext expressionContext) throws Exception {
		this.objectFacade =  new ObjectFacade(clazz.newInstance());
		this.table = initTableName(clazz, table);
		this.alias = initAlias(clazz, alias);
		this.fetchMode = fetchMode;
		this.joinType = joinType;
		this.expressionContext = expressionContext;
	}
	
	private String initTableName(Class<?> clazz, String tableName) {
		if (StringUtils.isBlank(tableName)) {
			Table table = clazz.getAnnotation(Table.class);
			AutoMapperException.NullRuntimeException(table, "对象%s没有@Table注解", clazz);
			tableName = table.name();
		} 
		AutoMapperException.StringisBlankRuntimeException(tableName, clazz + "对象表名不能为空或空字符串");
		return tableName;
	}
	
	//初始化别名，当别名是空值或空字符串，别名采用 "类名" + "_"
	private String initAlias(Class<?> clazz, String alias) {
		if (StringUtils.isBlank(alias)) {
			return StringUtils.substringAfterLast(clazz.getName(), ".") + "_";
		} else {
			return alias;
		}
	}

	public String getTable() throws Exception {
		TableFragment tableFragment = SqlFragmentFactory.getTableFragment(expressionContext, objectFacade, table, alias, fetchMode, joinType);
		return tableFragment.getTableFragment();
	}
	
	public List<String> getColumnNames() {
		List<String> list = new ArrayList<>();
		List<String> columnNames = objectFacade.getColumnNames();
		for (String column : columnNames) {
			list.add(alias + "." + column + " as " + alias + column);
		}
		return list;
	}

	public void setFetchMode(FetchMode fetchMode) {
		this.fetchMode = fetchMode;
	}

	public String getAlias() {
		return alias;
	}
	
	public FieldFacade getJoinColumnField() {
		return objectFacade.getJoinColumnField();
	}
		
	public Class<?> getOriginalClass() {
		return objectFacade.getOriginalObject().getClass();
	}
	
	public Class<?> getNestedResultsClassPath() {
		List<FieldFacade> list = objectFacade.getFieldFacades();
		for (FieldFacade fieldFacade : list) {
			if (fieldFacade.hasNestedResults()) {
				return fieldFacade.getNestedResultsClassPath();
			}
		}
		return null;
	}

	public SqlFragmentAssembler getCascadeSqlFragmentAssembler() {
		return cascadeSqlFragmentAssembler;
	}

	public void setCascadeSqlFragmentAssembler(SqlFragmentAssembler cascadeSqlFragmentAssembler) {
		this.cascadeSqlFragmentAssembler = cascadeSqlFragmentAssembler;
	}
}
